package com.neo.tiny.bpm.service.oa.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.neo.tiny.bpm.api.BpmProcessInstanceApi;
import com.neo.tiny.bpm.dto.task.BpmProcessInstanceCreateReqDTO;
import com.neo.tiny.bpm.entity.oa.BpmOALeaveDO;
import com.neo.tiny.bpm.enums.task.BpmProcessInstanceResultEnum;
import com.neo.tiny.bpm.mapper.BpmOALeaveMapper;
import com.neo.tiny.bpm.service.oa.BpmOALeaveService;
import com.neo.tiny.bpm.vo.oa.BpmOALeaveCreateReqVO;
import com.neo.tiny.bpm.vo.oa.BpmOALeavePageReqVO;
import com.neo.tiny.common.constant.ErrorCodeConstants;
import com.neo.tiny.common.exception.WebApiException;
import com.neo.tiny.query.LambdaQueryWrapperBase;
import com.neo.tiny.util.MyBatisUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @Description: OA 请假申请 Service 实现类
 * @Author: yqz
 * @CreateDate: 2022/10/19 23:00
 */
@Service
@AllArgsConstructor
public class BpmOALeaveServiceImpl extends ServiceImpl<BpmOALeaveMapper, BpmOALeaveDO> implements BpmOALeaveService {

    /**
     * OA 请假对应的流程定义 KEY
     */
    public static final String PROCESS_KEY = "diy_oa";

    private final BpmOALeaveMapper leaveMapper;

    private final BpmProcessInstanceApi processInstanceApi;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createLeave(Long userId, BpmOALeaveCreateReqVO createReqVO) {
        // 插入 OA 请假单
        long day = DateUtil.betweenDay(createReqVO.getStartTime(), createReqVO.getEndTime(), false);

        BpmOALeaveDO leaveDO = BeanUtil.copyProperties(createReqVO, BpmOALeaveDO.class);
        Optional.ofNullable(createReqVO.getType()).ifPresent(type -> leaveDO.setType(type.toString()));
        leaveDO.setUserId(userId);
        leaveDO.setDayNum(day);
        leaveDO.setResult(BpmProcessInstanceResultEnum.PROCESS.getResult());
        leaveMapper.insert(leaveDO);
        // 发起 BPM 流程
        Map<String, Object> processInstanceVariables = new HashMap<>();
        processInstanceVariables.put("day", day);

        BpmProcessInstanceCreateReqDTO dto = new BpmProcessInstanceCreateReqDTO();
        dto.setProcessDefinitionKey(PROCESS_KEY);
        dto.setVariables(processInstanceVariables);
        dto.setBusinessKey(String.valueOf(leaveDO.getId()));
        String processInstanceId = processInstanceApi.createProcessInstance(userId, dto);

        // 将工作流的编号，更新到 OA 请假单中
        this.update(new LambdaUpdateWrapper<BpmOALeaveDO>()
                .set(BpmOALeaveDO::getProcessInstanceId, processInstanceId)
                .eq(BpmOALeaveDO::getId, leaveDO.getId()));

        return leaveDO.getId();
    }

    @Override
    public IPage<BpmOALeaveDO> getLeavePage(Long userId, BpmOALeavePageReqVO pageReqVO) {
        return leaveMapper.selectPage(MyBatisUtils.buildPage(pageReqVO), new LambdaQueryWrapperBase<BpmOALeaveDO>()
                .eqIfPresent(BpmOALeaveDO::getUserId, userId)
                .eqIfPresent(BpmOALeaveDO::getResult, pageReqVO.getResult())
                .eqIfPresent(BpmOALeaveDO::getType, pageReqVO.getType())
                .likeIfPresent(BpmOALeaveDO::getReason, pageReqVO.getReason())
                .betweenIfPresent(BpmOALeaveDO::getCreateTime, pageReqVO.getBeginCreateTime(), pageReqVO.getEndCreateTime())
                .orderByDesc(BpmOALeaveDO::getCreateTime));

    }

    @Override
    public BpmOALeaveDO getLeave(Long id) {

        return leaveMapper.selectById(id);
    }

    @Override
    public void updateLeaveResult(Long id, Integer result) {
        validateLeaveExists(id);
        BpmOALeaveDO leaveDO = new BpmOALeaveDO();
        leaveDO.setId(id);
        leaveDO.setResult(result);
        leaveMapper.updateById(leaveDO);
    }

    private void validateLeaveExists(Long id) {
        if (leaveMapper.selectById(id) == null) {
            throw new WebApiException(ErrorCodeConstants.OA_LEAVE_NOT_EXISTS);
        }
    }

}
